//
// Created by twetec on 25-7-3.
//

#include "perception_rpc_caller_register_probe.h"

#include <boost/algorithm/string/trim.hpp>
#include <boost/json/object.hpp>
#include <boost/json/parse.hpp>
#include <boost/json/serialize.hpp>
#include <grpcpp/grpcpp.h>

#include <network_prober/sys_config/sys_config.h>
#include <network_prober/database/memory_db_holder.h>
#include <network_prober/database/memory_db_model.h>

namespace network_prober::rpc
{
/**
 * 解析请求头
 */
static std::string s_parseHttpRequestHeader(const std::string& requestHeader)
{
    // 如果请求头为空
    if (requestHeader.empty()) return {};

    // 请求头解析处理
    boost::json::object headerJSON;
    // 解析请求头
    std::string headerLine{};
    std::istringstream headerIss{requestHeader};

    // 每次读取一行键值对
    while (std::getline(headerIss, headerLine, '\n')) {
        // 一行键值对
        std::istringstream lineIss{headerLine};

        // 键
        std::string key{};
        std::getline(lineIss, key, ':');

        // 值
        std::string value{};
        std::getline(lineIss, value, ':');
        boost::trim(value); // 移除字符串两边的空字符

        // 设置到json中
        headerJSON[key] = boost::json::string{value};
    }

    return boost::json::serialize(headerJSON).c_str();
}

PerceptionRPCCallerRegisterProbe::PerceptionRPCCallerRegisterProbe()
{
    // 1、获取感知系统配置信息
    std::string perceptionIP = sys_config::SysConfig::getInstance().perceptionIP();
    std::size_t perceptionPort = sys_config::SysConfig::getInstance().perceptionPort();

    // 2、构建通道参数
    grpc::ChannelArguments channelArguments;
    // channelArguments.SetChannelArgs()
    // channelArguments.SetInt(GRPC_ARG_KEEPALIVE_TIME_MS, 30 * 1000 /*45 sec*/);  // 每隔多长时间发送一次心跳
    // channelArguments.SetInt(GRPC_ARG_KEEPALIVE_TIMEOUT_MS, 20 * 1000 /*10 sec*/); // 发送心跳后，响应超时时间
    // channelArguments.SetInt(GRPC_ARG_KEEPALIVE_PERMIT_WITHOUT_CALLS, 1);    // 是否允许发送心跳数据

    // 2、根据监听目标配置，指定连接通道（主机地址和端口，后面的参数表示不适用SSL）
    std::shared_ptr<grpc::Channel> channel = grpc::CreateCustomChannel(
        perceptionIP + ":" + std::to_string(perceptionPort),
        grpc::InsecureChannelCredentials(),
        channelArguments
    );

    // std::shared_ptr<grpc::Channel> channel = grpc::CreateChannel(
    //     perceptionIP + ":" + std::to_string(perceptionPort),
    //     grpc::InsecureChannelCredentials()
    // );

    // 3、创建远程调用代理(存根对象)
    m_RPCClientStubPtr = network_perception::rpc::NetworkPerceptionServer::NewStub(channel);
}

void PerceptionRPCCallerRegisterProbe::callImpl()
{
    // 存储请求的上下文信息
    grpc::ClientContext context;

    // 请求信息
    network_perception::rpc::RegisterProbeRequest request;
    // 基础参数
    request.set_version(sys_config::SysConfig::getInstance().proberVersion());
    request.set_machineid(sys_config::SysConfig::getInstance().proberUUID());
    request.set_productuuid(sys_config::SysConfig::getInstance().productUUID());
    request.set_publicmodel(sys_config::SysConfig::getInstance().proberPublicModel());
    // 硬件参数 (对象内存已经开辟)
    auto requestHardware = request.mutable_hardware();
    requestHardware->set_cpumodel(sys_config::SysConfig::getInstance().proberCPUModel());
    requestHardware->set_cpucores(std::to_string(sys_config::SysConfig::getInstance().proberCPUCores()));
    requestHardware->set_memorybytes(sys_config::SysConfig::getInstance().proberMemoryBytes());
    requestHardware->set_diskbytes(sys_config::SysConfig::getInstance().proberDiskBytes());
    // 所有物理网卡
    auto proberInterfaceConfs = sys_config::SysConfig::getInstance().proberInterfaceConfs();
    for (auto it = proberInterfaceConfs.begin(); it != proberInterfaceConfs.end(); it ++ ) {
        // 让grpc开辟一块空间
        auto requestEthernetInterface = requestHardware->add_nics();
        requestEthernetInterface->set_name(it->name);
        requestEthernetInterface->set_ipv4address(it->IPv4Address);
        requestEthernetInterface->set_ipv4subnetmask(it->IPv4SubnetMask);
        requestEthernetInterface->set_ipv4gateway(it->IPv4Gateway);
        requestEthernetInterface->set_ipv6address(it->IPv6Address);
        requestEthernetInterface->set_ipv6subnetmask(it->IPv6SubnetMask);
        requestEthernetInterface->set_ipv6gateway(it->IPv6Gateway);
        requestEthernetInterface->set_speed(it->speed);
        requestEthernetInterface->set_bandwidth(it->bandwidth);
        requestEthernetInterface->set_macaddress(it->macAddress);
    }

    // 响应信息
    network_perception::rpc::RegisterProbeResponse response;

    // The actual RPC.
    std::mutex mutx;
    std::condition_variable cv;
    bool done = false;
    grpc::Status status;

    // 注册探针 (异步)
    m_RPCClientStubPtr->async()->registerProbe(&context, &request, &response, [&mutx, &cv, &done, &status](grpc::Status s) {
        // 响应结果时，先加锁，再修改变量
        std::unique_lock<std::mutex> lock(mutx);
        status = std::move(s);
        done = true;
        cv.notify_one();
    });

    std::unique_lock<std::mutex> lock(mutx);
    cv.wait(lock, [&done]() { return done; });  // 程序会暂停在这里

    // 如果注册失败，则抛出异常
    if (!status.ok()) {
        std::stringstream ss;
        ss << "探针注册失败: " << status.error_message() << "..." << std::endl;
        SPDLOG_ERROR(ss.str());
        throw std::runtime_error(ss.str());
    }

    // 探针注册服务端响应失败
    if (response.code() != RespCode::SUCCESS) {
        std::stringstream ss;
        ss << "探针注册服务端响应失败: " << response.msg() << "..." << std::endl;
        throw std::runtime_error(ss.str());
    }

    SPDLOG_INFO("探针注册成功...");

    // 观测任务
    auto probeTasks = response.data().probetasks();

    // 将观测目标存入数据表
    std::vector<network_prober::database::ObservedTargetModel> observedTargetModels;
    observedTargetModels.reserve(probeTasks.size());

    for (auto it = probeTasks.begin(); it != probeTasks.end(); it++) {
        // 构建观测模型
        network_prober::database::ObservedTargetModel observedTargetModel;

        observedTargetModel.uuid = it->uuid();
        observedTargetModel.interface = it->interface();
        observedTargetModel.address = it->address();
        observedTargetModel.port = it->port();
        observedTargetModel.protocol = it->protocol();
        observedTargetModel.responseCode = it->responsecode();
        observedTargetModel.ignoreTsl = it->ignoretsl();
        observedTargetModel.requestMethod = it->requestmethod();
        observedTargetModel.requestHeader = s_parseHttpRequestHeader(it->requestheader());
        observedTargetModel.requestBody = it->requestbody();
        observedTargetModel.responseChallenge = it->responsechallenge();
        observedTargetModel.userName = it->username();
        observedTargetModel.password = it->password();
        observedTargetModel.databaseName = it->databasename();
        observedTargetModel.queryStatement = it->querystatement();
        observedTargetModel.matchCondition = it->matchcondition();
        observedTargetModel.keyWords = it->keywords();

        observedTargetModels.push_back(std::move(observedTargetModel));
    }

    // 批量插入观测目标
    if (!observedTargetModels.empty()) {
        network_prober::database::MemoryDBHolder::getInstance().batchInsertObservedTargets(observedTargetModels);
    }

    // 备份目标
    auto backupTasks = response.data().backuptasks();

    // 将备份目标存入数据表
    std::vector<network_prober::database::DeviceModel>  deviceModels;
    deviceModels.reserve(backupTasks.size());
    // 将备份内容存入数据表
    std::vector<network_prober::database::BackupTaskResultModel> backupTaskResultModels;
    backupTaskResultModels.reserve(backupTasks.size());

    // 循环备份目标，转换为数据库模型
    for (auto it = backupTasks.begin(); it != backupTasks.end(); it++) {
        // 构建备份目标
        network_prober::database::DeviceModel deviceModel;

        deviceModel.uuid = it->uuid();
        deviceModel.interface = it->interface();
        deviceModel.address = it->address();
        deviceModel.backupDate = it->backupdate();
        deviceModel.command = it->command();
        deviceModel.protocol = it->protocol();
        deviceModel.account = it->account();
        deviceModel.password = it->password();
        deviceModel.privilegedPassword = it->privilegedpassword();
        deviceModel.port = it->port();

        deviceModels.push_back(std::move(deviceModel));

        // 构建备份数据
        database::MemoryDBHolder::getInstance().insertBackupTaskResult(it->uuid(), it->backupdata(), std::chrono::time_point_cast<std::chrono::seconds>(std::chrono::system_clock::now()).time_since_epoch().count());
    }

    // 批量插入备份目标
    if (!deviceModels.empty()) {
        database::MemoryDBHolder::getInstance().batchInsertDevices(deviceModels);
    }

    // 存储探针的secretKey
    network_prober::sys_config::SysConfig::getInstance().setProberSecretKey(response.data().secretkey());
}

}